package start.spring.basic.flowable.service.process.impl;

import java.io.InputStream;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import org.flowable.bpmn.constants.BpmnXMLConstants;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.bpmn.model.StartEvent;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricActivityInstanceQuery;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ruoyi.common.core.exception.ServiceException;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import start.spring.basic.flowable.common.ProcessConstants;
import start.spring.basic.flowable.common.TaskConstants;
import start.spring.basic.flowable.dao.WfApplyRecordMapper;
import start.spring.basic.flowable.dao.WfDeployFormMapper;
import start.spring.basic.flowable.entity.WfApplyRecord;
import start.spring.basic.flowable.entity.WfDeployForm;
import start.spring.basic.flowable.enums.flowable.ApprovalStatus;
import start.spring.basic.flowable.enums.flowable.ProcessStatus;
import start.spring.basic.flowable.service.FlowableBaseServiceImpl;
import start.spring.basic.flowable.service.flowable.IWfTaskService;
import start.spring.basic.flowable.service.process.IWfProcessService;
import start.spring.basic.flowable.utils.flowable.FlowableUtils;
import start.spring.basic.flowable.utils.flowable.ModelUtils;
import start.spring.basic.flowable.utils.flowable.ProcessFormUtils;
import start.spring.basic.flowable.utils.flowable.ProcessUtils;
import start.spring.basic.flowable.vo.flowable.FormConf;
import start.spring.basic.flowable.vo.flowable.ProcessQuery;
import start.spring.basic.flowable.vo.flowable.WfDefinitionVo;
import start.spring.basic.flowable.vo.flowable.WfDetailVo;
import start.spring.basic.flowable.vo.flowable.WfProcNodeVo;
import start.spring.basic.flowable.vo.flowable.WfTaskVo;
import start.spring.basic.flowable.vo.flowable.WfViewerVo;
import start.spring.basic.page.PageQuery;
import start.spring.basic.page.PageResult;
import start.spring.basic.response.ResponseData;
import start.spring.basic.ry.core.utils.StringUtils;
import start.spring.basic.util.PageUtil;
import start.spring.basic.util.common.DateUtil;
import start.spring.basic.util.common.StringUtil;

/**
 * @author KonBAI
 * @createTime 2022/3/24 18:57
 */
@Service
public class WfProcessServiceImpl extends FlowableBaseServiceImpl implements IWfProcessService {
	
	@Autowired
    private IWfTaskService wfTaskService;
	
	@Autowired
    private WfApplyRecordMapper wfApplyRecordMapper;
    
	@Autowired
    private WfDeployFormMapper deployFormMapper;

    /**
     * 流程定义列表
     *
     * @param pageQuery 分页参数
     * @return 流程定义分页列表数据
     */
    @Override
    public PageResult<WfDefinitionVo> selectPageStartProcessList(PageQuery pageQuery, ProcessQuery processQuery) {
        // 流程定义列表数据查询
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
            .latestVersion()
            .active()
            .orderByProcessDefinitionId()
            .asc();
        // 构建搜索条件
        ProcessUtils.buildProcessSearch(processDefinitionQuery, processQuery);
        long pageTotal = processDefinitionQuery.count();
        if (pageTotal <= 0) {
        	return super.getPageResult(new PageUtil<>());
        }
        int offset = pageQuery.getSize() * (pageQuery.getCurrent() - 1);
        List<ProcessDefinition> definitionList = processDefinitionQuery.listPage(offset, pageQuery.getSize());

        List<WfDefinitionVo> definitionVoList = new ArrayList<>();
        for (ProcessDefinition processDefinition : definitionList) {
            String deploymentId = processDefinition.getDeploymentId();
            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
            WfDefinitionVo vo = new WfDefinitionVo();
            vo.setDefinitionId(processDefinition.getId());
            vo.setProcessKey(processDefinition.getKey());
            vo.setProcessName(processDefinition.getName());
            vo.setVersion(processDefinition.getVersion());
            vo.setDeploymentId(processDefinition.getDeploymentId());
            vo.setSuspended(processDefinition.isSuspended());
            // 流程定义时间
            vo.setCategory(deployment.getCategory());
            vo.setDeploymentTime(deployment.getDeploymentTime());
            definitionVoList.add(vo);
        }
        PageUtil<WfDefinitionVo> pageUtil = new PageUtil<>();
        pageUtil.setCurrentPage(pageQuery.getCurrent());
        pageUtil.setNumPerPage(pageQuery.getSize());
        pageUtil.setTotalRecords(pageTotal);
        pageUtil.setResultList(definitionVoList);
        return super.getPageResult(pageUtil);
    }

    @Override
    public List<WfDefinitionVo> selectStartProcessList(ProcessQuery processQuery) {
        // 流程定义列表数据查询
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
                .latestVersion()
                .active()
                .orderByProcessDefinitionKey()
                .asc();
        // 构建搜索条件
        ProcessUtils.buildProcessSearch(processDefinitionQuery, processQuery);

        List<ProcessDefinition> definitionList = processDefinitionQuery.list();

        List<WfDefinitionVo> definitionVoList = new ArrayList<>();
        for (ProcessDefinition processDefinition : definitionList) {
            String deploymentId = processDefinition.getDeploymentId();
            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
            WfDefinitionVo vo = new WfDefinitionVo();
            vo.setDefinitionId(processDefinition.getId());
            vo.setProcessKey(processDefinition.getKey());
            vo.setProcessName(processDefinition.getName());
            vo.setVersion(processDefinition.getVersion());
            vo.setDeploymentId(processDefinition.getDeploymentId());
            vo.setSuspended(processDefinition.isSuspended());
            // 流程定义时间
            vo.setCategory(deployment.getCategory());
            vo.setDeploymentTime(deployment.getDeploymentTime());
            definitionVoList.add(vo);
        }
        return definitionVoList;
    }

    @Override
    public PageResult<WfTaskVo> selectPageOwnProcessList(ProcessQuery processQuery, PageQuery pageQuery) {
        
        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
            .startedBy(String.valueOf(super.getSysUser().getUserId())).includeProcessVariables();
        if(!StringUtil.isEmpty(processQuery.getProcessKey())) {
        	historicProcessInstanceQuery.processDefinitionKey(processQuery.getProcessKey());
        }
        if(!StringUtil.isEmpty(processQuery.getProcessName())) {
        	historicProcessInstanceQuery.processDefinitionName(processQuery.getProcessName());
        }
        if(!StringUtil.isEmpty(processQuery.getCategory())) {
        	historicProcessInstanceQuery.processDefinitionCategory(processQuery.getCategory());
        }
        historicProcessInstanceQuery.orderByProcessInstanceStartTime().desc();
        
        long pageTotal = historicProcessInstanceQuery.count();
        if (pageTotal <= 0) {
        	return super.getPageResult(new PageUtil<>());
        }
        int offset = pageQuery.getSize() * (pageQuery.getCurrent() - 1);
        
        List<HistoricProcessInstance> historicProcessInstances = 
        		historicProcessInstanceQuery.listPage(offset, pageQuery.getSize());
        
        List<WfTaskVo> taskVoList = new ArrayList<>();
        for (HistoricProcessInstance hisIns : historicProcessInstances) {
            WfTaskVo taskVo = new WfTaskVo();
            String processStatus = null;
            // 兼容旧流程
            if (processStatus == null) {
                processStatus = ObjectUtil.isNull(hisIns.getEndTime()) ? ProcessStatus.RUNNING.getRemark() : ProcessStatus.COMPLETED.getRemark();
            }
            taskVo.setProcessStatus(processStatus);
            taskVo.setCreateTime(hisIns.getStartTime());
            taskVo.setFinishTime(hisIns.getEndTime());
            taskVo.setProcInsId(hisIns.getId());
            taskVo.setDeployId(hisIns.getDeploymentId());
            taskVo.setProcDefId(hisIns.getProcessDefinitionId());
            taskVo.setProcDefName(hisIns.getProcessDefinitionName());
            taskVo.setProcDefVersion(hisIns.getProcessDefinitionVersion());
            taskVo.setCategory(String.valueOf(hisIns.getProcessVariables().get(ProcessConstants.PROCESS_CATEGORY)));
            taskVo.setBusinessKey(hisIns.getBusinessKey());
            taskVoList.add(taskVo);
        }
        PageUtil<WfTaskVo> pageUtil = new PageUtil<>();
        pageUtil.setCurrentPage(pageQuery.getCurrent());
        pageUtil.setNumPerPage(pageQuery.getSize());
        pageUtil.setTotalRecords(pageTotal);
        pageUtil.setResultList(taskVoList);
        return super.getPageResult(pageUtil);
    	
    }

    @Override
    public List<WfTaskVo> selectOwnProcessList(ProcessQuery processQuery) {
//        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
//                .startedBy(TaskUtils.getUserId())
//                .orderByProcessInstanceStartTime()
//                .desc();
//        // 构建搜索条件
//        ProcessUtils.buildProcessSearch(historicProcessInstanceQuery, processQuery);
//        List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.list();
//        List<WfTaskVo> taskVoList = new ArrayList<>();
//        for (HistoricProcessInstance hisIns : historicProcessInstances) {
//            WfTaskVo taskVo = new WfTaskVo();
//            taskVo.setCreateTime(hisIns.getStartTime());
//            taskVo.setFinishTime(hisIns.getEndTime());
//            taskVo.setProcInsId(hisIns.getId());
//
//            // 计算耗时
//            if (Objects.nonNull(hisIns.getEndTime())) {
//                taskVo.setDuration(DateUtils.getDatePoor(hisIns.getEndTime(), hisIns.getStartTime()));
//            } else {
//                taskVo.setDuration(DateUtils.getDatePoor(DateUtils.getNowDate(), hisIns.getStartTime()));
//            }
//            // 流程部署实例信息
//            Deployment deployment = repositoryService.createDeploymentQuery()
//                    .deploymentId(hisIns.getDeploymentId()).singleResult();
//            taskVo.setDeployId(hisIns.getDeploymentId());
//            taskVo.setProcDefId(hisIns.getProcessDefinitionId());
//            taskVo.setProcDefName(hisIns.getProcessDefinitionName());
//            taskVo.setProcDefVersion(hisIns.getProcessDefinitionVersion());
//            taskVo.setCategory(deployment.getCategory());
//            // 当前所处流程
//            List<Task> taskList = taskService.createTaskQuery().processInstanceId(hisIns.getId()).includeIdentityLinks().list();
//            if (CollUtil.isNotEmpty(taskList)) {
//                taskVo.setTaskName(taskList.stream().map(Task::getName).filter(StringUtils::isNotEmpty).collect(Collectors.joining(",")));
//            }
//            taskVoList.add(taskVo);
//        }
//        return taskVoList;
    	return null;
    }

    @Override
    public PageResult<WfTaskVo> selectPageTodoProcessList(ProcessQuery processQuery, PageQuery pageQuery) {
        
        TaskQuery taskQuery = taskService.createTaskQuery()
            .active()
            .includeProcessVariables()
            .taskCandidateOrAssigned(String.valueOf(super.getSysUser().getUserId()));
        
        if (StringUtils.isNotBlank(processQuery.getProcessKey())) {
        	taskQuery.processDefinitionKeyLike("%" + processQuery.getProcessKey() + "%");
        }
        if (StringUtils.isNotBlank(processQuery.getProcessName())) {
        	taskQuery.processDefinitionNameLike("%" + processQuery.getProcessName() + "%");
        }
        if(StringUtils.isNotBlank(processQuery.getBeginTjsj())) {
        	try {
				taskQuery.taskCreatedAfter(DateUtil.parse((processQuery.getBeginTjsj() + " 00:00:00"), DateUtil.FORMAT_YMDHMS_L));
			} catch (ParseException e) {
				e.printStackTrace();
			}
        }
        if(StringUtils.isNotBlank(processQuery.getEndTjsj())) {
        	try {
				taskQuery.taskCreatedBefore(DateUtil.parse((processQuery.getEndTjsj() + " 23:59:59"), DateUtil.FORMAT_YMDHMS_L));
			} catch (ParseException e) {
				e.printStackTrace();
			}
        }
        taskQuery.orderByTaskCreateTime().desc();
        
        long pageTotal = taskQuery.count();
        if (pageTotal <= 0) {
        	return super.getPageResult(new PageUtil<>());
        }
        int offset = pageQuery.getSize() * (pageQuery.getCurrent() - 1);
        List<Task> taskList = taskQuery.listPage(offset, pageQuery.getSize());
        
        List<WfTaskVo> flowList = new ArrayList<>();
        for (Task task : taskList) {
            WfTaskVo flowTask = new WfTaskVo();
            // 当前流程信息
            flowTask.setTaskId(task.getId());
            flowTask.setTaskDefKey(task.getTaskDefinitionKey());
            flowTask.setCreateTime(task.getCreateTime());
            flowTask.setProcDefId(task.getProcessDefinitionId());
            flowTask.setTaskName(task.getName());
            // 流程定义信息
            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(task.getProcessDefinitionId())
                .singleResult();
            flowTask.setDeployId(pd.getDeploymentId());
            flowTask.setProcDefName(pd.getName());
            flowTask.setProcDefVersion(pd.getVersion());
            flowTask.setProcInsId(task.getProcessInstanceId());
            
            // 流程发起人信息
            flowTask.setStartUserId(Long.parseLong(
            		task.getProcessVariables().get(BpmnXMLConstants.ATTRIBUTE_EVENT_START_INITIATOR).toString()));
            flowTask.setStartDeptName(String.valueOf(
            		task.getProcessVariables().get(ProcessConstants.PROCESS_STARTER_DEPTNAME)));
            flowTask.setStartUserNickName(String.valueOf(
            		task.getProcessVariables().get(ProcessConstants.PROCESS_STARTER_NICKNAME)));
            //业务数据主键
            flowTask.setBusinessKey(String.valueOf(
            		task.getProcessVariables().get(ProcessConstants.BUSINESS_KEY)));
            //摘要
            flowTask.setSummary(String.valueOf(
            		task.getProcessVariables().get(ProcessConstants.PROCESS_APPLY_SUMMARY)));
            //流程申请时间
            flowTask.setApplyTime(String.valueOf(
            		task.getProcessVariables().get(ProcessConstants.PROCESS_START_TIME)));

            // 流程变量
            flowTask.setProcVars(task.getProcessVariables());

            flowList.add(flowTask);
        }
        PageUtil<WfTaskVo> pageUtil = new PageUtil<>();
        pageUtil.setCurrentPage(pageQuery.getCurrent());
        pageUtil.setNumPerPage(pageQuery.getSize());
        pageUtil.setTotalRecords(pageTotal);
        pageUtil.setResultList(flowList);
        return super.getPageResult(pageUtil);
    }

    @Override
    public List<WfTaskVo> selectTodoProcessList(ProcessQuery processQuery) {
//        TaskQuery taskQuery = taskService.createTaskQuery()
//                .active()
//                .includeProcessVariables()
//                .taskCandidateOrAssigned(TaskUtils.getUserId())
//                .taskCandidateGroupIn(TaskUtils.getCandidateGroup())
//                .orderByTaskCreateTime().desc();
//        // 构建搜索条件
//        ProcessUtils.buildProcessSearch(taskQuery, processQuery);
//        List<Task> taskList = taskQuery.list();
//        List<WfTaskVo> taskVoList = new ArrayList<>();
//        for (Task task : taskList) {
//            WfTaskVo taskVo = new WfTaskVo();
//            // 当前流程信息
//            taskVo.setTaskId(task.getId());
//            taskVo.setTaskDefKey(task.getTaskDefinitionKey());
//            taskVo.setCreateTime(task.getCreateTime());
//            taskVo.setProcDefId(task.getProcessDefinitionId());
//            taskVo.setTaskName(task.getName());
//            // 流程定义信息
//            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
//                    .processDefinitionId(task.getProcessDefinitionId())
//                    .singleResult();
//            taskVo.setDeployId(pd.getDeploymentId());
//            taskVo.setProcDefName(pd.getName());
//            taskVo.setProcDefVersion(pd.getVersion());
//            taskVo.setProcInsId(task.getProcessInstanceId());
//
//            // 流程发起人信息
//            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
//                    .processInstanceId(task.getProcessInstanceId())
//                    .singleResult();
//            Long userId = Long.parseLong(historicProcessInstance.getStartUserId());
//            String nickName = userService.selectNickNameById(userId);
//            taskVo.setStartUserId(userId);
//            taskVo.setStartUserName(nickName);
//
//            taskVoList.add(taskVo);
//        }
//        return taskVoList;
    	return null;
    }

    @Override
    public PageResult<WfTaskVo> selectPageClaimProcessList(ProcessQuery processQuery, PageQuery pageQuery) {
    	
    	List<String> groupIds = new ArrayList<>();
    	
    	//查询结果不包括指定用户的任务，指定用户的任务直接进入待办不需要签收
    	
    	//分配给当前用户角色的任务可签收
    	for(Long roleId:super.getSysUser().getRoleIds()) {
    		groupIds.add(TaskConstants.ROLE_GROUP_PREFIX + String.valueOf(roleId));
    	}
    	
    	//分配给当前用户所在部门的任务可签收
    	groupIds.add(TaskConstants.DEPT_GROUP_PREFIX + String.valueOf(super.getSysUser().getDeptId()));
        
        TaskQuery taskQuery = taskService.createTaskQuery()
            .active()
            .includeProcessVariables()
            .taskCandidateUser(String.valueOf(super.getSysUser().getUserId()))
            .taskCandidateGroupIn(groupIds);
        
        if (StringUtils.isNotBlank(processQuery.getProcessKey())) {
        	taskQuery.processDefinitionKeyLike("%" + processQuery.getProcessKey() + "%");
        }
        if (StringUtils.isNotBlank(processQuery.getProcessName())) {
        	taskQuery.processDefinitionNameLike("%" + processQuery.getProcessName() + "%");
        }
        taskQuery.orderByTaskCreateTime().desc();
        
        long pageTotal = taskQuery.count();
        if (pageTotal <= 0) {
        	return super.getPageResult(new PageUtil<>());
        }
        int offset = pageQuery.getSize() * (pageQuery.getCurrent() - 1);
        
        List<Task> taskList = taskQuery.listPage(offset, pageQuery.getSize());
        List<WfTaskVo> flowList = new ArrayList<>();
        for (Task task : taskList) {
            WfTaskVo flowTask = new WfTaskVo();
            // 当前流程信息
            flowTask.setTaskId(task.getId());
            flowTask.setTaskDefKey(task.getTaskDefinitionKey());
            flowTask.setProcDefId(task.getProcessDefinitionId());
            flowTask.setTaskName(task.getName());
            // 流程定义信息
            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(task.getProcessDefinitionId())
                .singleResult();
            flowTask.setDeployId(pd.getDeploymentId());
            flowTask.setProcDefName(pd.getName());
            flowTask.setProcDefVersion(pd.getVersion());
            flowTask.setProcInsId(task.getProcessInstanceId());

            // 流程发起人信息
            flowTask.setStartUserId(Long.parseLong(
            		task.getProcessVariables().get(BpmnXMLConstants.ATTRIBUTE_EVENT_START_INITIATOR).toString()));
            flowTask.setStartUserNickName(String.valueOf(
            		task.getProcessVariables().get(ProcessConstants.PROCESS_STARTER_NICKNAME)));
            flowTask.setStartDeptName(String.valueOf(
            		task.getProcessVariables().get(ProcessConstants.PROCESS_STARTER_DEPTNAME)));
            //业务数据主键
            flowTask.setBusinessKey(String.valueOf(
            		task.getProcessVariables().get(ProcessConstants.BUSINESS_KEY)));
            //摘要
            flowTask.setSummary(String.valueOf(
            		task.getProcessVariables().get(ProcessConstants.PROCESS_APPLY_SUMMARY)));
            //流程申请时间
            flowTask.setApplyTime(String.valueOf(
            		task.getProcessVariables().get(ProcessConstants.PROCESS_START_TIME)));

            flowList.add(flowTask);
        }
        PageUtil<WfTaskVo> pageUtil = new PageUtil<>();
        pageUtil.setCurrentPage(pageQuery.getCurrent());
        pageUtil.setNumPerPage(pageQuery.getSize());
        pageUtil.setTotalRecords(pageTotal);
        pageUtil.setResultList(flowList);
        return super.getPageResult(pageUtil);
        
    }

    @Override
    public List<WfTaskVo> selectClaimProcessList(ProcessQuery processQuery) {
//        TaskQuery taskQuery = taskService.createTaskQuery()
//                .active()
//                .includeProcessVariables()
//                .taskCandidateUser(TaskUtils.getUserId())
//                .taskCandidateGroupIn(TaskUtils.getCandidateGroup())
//                .orderByTaskCreateTime().desc();
//        // 构建搜索条件
//        ProcessUtils.buildProcessSearch(taskQuery, processQuery);
//        List<Task> taskList = taskQuery.list();
//        List<WfTaskVo> flowList = new ArrayList<>();
//        for (Task task : taskList) {
//            WfTaskVo flowTask = new WfTaskVo();
//            // 当前流程信息
//            flowTask.setTaskId(task.getId());
//            flowTask.setTaskDefKey(task.getTaskDefinitionKey());
//            flowTask.setCreateTime(task.getCreateTime());
//            flowTask.setProcDefId(task.getProcessDefinitionId());
//            flowTask.setTaskName(task.getName());
//            // 流程定义信息
//            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
//                    .processDefinitionId(task.getProcessDefinitionId())
//                    .singleResult();
//            flowTask.setDeployId(pd.getDeploymentId());
//            flowTask.setProcDefName(pd.getName());
//            flowTask.setProcDefVersion(pd.getVersion());
//            flowTask.setProcInsId(task.getProcessInstanceId());
//
//            // 流程发起人信息
//            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
//                    .processInstanceId(task.getProcessInstanceId())
//                    .singleResult();
//            Long userId = Long.parseLong(historicProcessInstance.getStartUserId());
//            String nickName = userService.selectNickNameById(userId);
//            flowTask.setStartUserId(userId);
//            flowTask.setStartUserName(nickName);
//
//            flowList.add(flowTask);
//        }
//        return flowList;
    	return null;
    }

    @Override
    public PageResult<WfTaskVo> selectPageFinishedProcessList(ProcessQuery processQuery, PageQuery pageQuery) {
    	
        HistoricTaskInstanceQuery taskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
            .includeProcessVariables()
            .finished()
            .taskAssignee(String.valueOf(super.getSysUser().getUserId()))
            .orderByHistoricTaskInstanceEndTime()
            .desc();
        // 构建搜索条件
        ProcessUtils.buildProcessSearch(taskInstanceQuery, processQuery);
        
        long pageTotal = taskInstanceQuery.count();
        if (pageTotal <= 0) {
        	return super.getPageResult(new PageUtil<>());
        }
        int offset = pageQuery.getSize() * (pageQuery.getCurrent() - 1);
        
        List<HistoricTaskInstance> historicTaskInstanceList = taskInstanceQuery.listPage(offset, pageQuery.getSize());
        List<WfTaskVo> hisTaskList = new ArrayList<>();
        for (HistoricTaskInstance histTask : historicTaskInstanceList) {
            WfTaskVo flowTask = new WfTaskVo();
            // 当前流程信息
            flowTask.setTaskId(histTask.getId());
            // 审批人员信息
            flowTask.setCreateTime(histTask.getCreateTime());
            flowTask.setFinishTime(histTask.getEndTime());
            flowTask.setProcDefId(histTask.getProcessDefinitionId());
            flowTask.setTaskDefKey(histTask.getTaskDefinitionKey());
            flowTask.setTaskName(histTask.getName());

            // 流程定义信息
            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(histTask.getProcessDefinitionId())
                .singleResult();
            flowTask.setDeployId(pd.getDeploymentId());
            flowTask.setProcDefName(pd.getName());
            flowTask.setProcDefVersion(pd.getVersion());
            flowTask.setProcInsId(histTask.getProcessInstanceId());
            flowTask.setHisProcInsId(histTask.getProcessInstanceId());
            
            // 流程发起人信息
            flowTask.setStartUserId(Long.parseLong(
            		histTask.getProcessVariables().get(BpmnXMLConstants.ATTRIBUTE_EVENT_START_INITIATOR).toString()));
            flowTask.setStartDeptName(String.valueOf(
            		histTask.getProcessVariables().get(ProcessConstants.PROCESS_STARTER_DEPTNAME)));
            flowTask.setStartUserNickName(String.valueOf(
            		histTask.getProcessVariables().get(ProcessConstants.PROCESS_STARTER_NICKNAME)));
            //业务数据主键
            flowTask.setBusinessKey(String.valueOf(
            		histTask.getProcessVariables().get(ProcessConstants.BUSINESS_KEY)));
            //摘要
            flowTask.setSummary(String.valueOf(
            		histTask.getProcessVariables().get(ProcessConstants.PROCESS_APPLY_SUMMARY)));
            //流程申请时间
            flowTask.setApplyTime(String.valueOf(
            		histTask.getProcessVariables().get(ProcessConstants.PROCESS_START_TIME)));
            
            // 流程变量
            flowTask.setProcVars(histTask.getProcessVariables());

            hisTaskList.add(flowTask);
        }
        
        PageUtil<WfTaskVo> pageUtil = new PageUtil<>();
        pageUtil.setCurrentPage(pageQuery.getCurrent());
        pageUtil.setNumPerPage(pageQuery.getSize());
        pageUtil.setTotalRecords(pageTotal);
        pageUtil.setResultList(hisTaskList);
        return super.getPageResult(pageUtil);
    }

    @Override
    public List<WfTaskVo> selectFinishedProcessList(ProcessQuery processQuery) {
//        HistoricTaskInstanceQuery taskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
//                .includeProcessVariables()
//                .finished()
//                .taskAssignee(TaskUtils.getUserId())
//                .orderByHistoricTaskInstanceEndTime()
//                .desc();
//        // 构建搜索条件
//        ProcessUtils.buildProcessSearch(taskInstanceQuery, processQuery);
//        List<HistoricTaskInstance> historicTaskInstanceList = taskInstanceQuery.list();
//        List<WfTaskVo> hisTaskList = new ArrayList<>();
//        for (HistoricTaskInstance histTask : historicTaskInstanceList) {
//            WfTaskVo flowTask = new WfTaskVo();
//            // 当前流程信息
//            flowTask.setTaskId(histTask.getId());
//            // 审批人员信息
//            flowTask.setCreateTime(histTask.getCreateTime());
//            flowTask.setFinishTime(histTask.getEndTime());
//            flowTask.setDuration(DateUtil.formatBetween(histTask.getDurationInMillis(), BetweenFormatter.Level.SECOND));
//            flowTask.setProcDefId(histTask.getProcessDefinitionId());
//            flowTask.setTaskDefKey(histTask.getTaskDefinitionKey());
//            flowTask.setTaskName(histTask.getName());
//
//            // 流程定义信息
//            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
//                    .processDefinitionId(histTask.getProcessDefinitionId())
//                    .singleResult();
//            flowTask.setDeployId(pd.getDeploymentId());
//            flowTask.setProcDefName(pd.getName());
//            flowTask.setProcDefVersion(pd.getVersion());
//            flowTask.setProcInsId(histTask.getProcessInstanceId());
//            flowTask.setHisProcInsId(histTask.getProcessInstanceId());
//
//            // 流程发起人信息
//            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
//                    .processInstanceId(histTask.getProcessInstanceId())
//                    .singleResult();
//            Long userId = Long.parseLong(historicProcessInstance.getStartUserId());
//            String nickName = userService.selectNickNameById(userId);
//            flowTask.setStartUserId(userId);
//            flowTask.setStartUserName(nickName);
//
//            // 流程变量
//            flowTask.setProcVars(histTask.getProcessVariables());
//
//            hisTaskList.add(flowTask);
//        }
//        return hisTaskList;
    	return null;
    }

    @Override
    public FormConf selectFormContent(String definitionId, String deployId, String procInsId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(definitionId);
        if (ObjectUtil.isNull(bpmnModel)) {
            throw new RuntimeException("获取流程设计失败！");
        }
        StartEvent startEvent = ModelUtils.getStartEvent(bpmnModel);
        WfDeployForm deployForm = deployFormMapper.selectOne(new LambdaQueryWrapper<WfDeployForm>()
            .eq(WfDeployForm::getDeployId, deployId)
            .eq(WfDeployForm::getFormKey, startEvent.getFormKey())
            .eq(WfDeployForm::getNodeKey, startEvent.getId()));
        FormConf formConf = JSONObject.parseObject(deployForm.getContent(), FormConf.class);
        if (ObjectUtil.isNull(formConf)) {
            throw new RuntimeException("获取流程表单失败！");
        }
        if (ObjectUtil.isNotEmpty(procInsId)) {
            // 获取流程实例
            HistoricProcessInstance historicProcIns = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(procInsId)
                .includeProcessVariables()
                .singleResult();
            // 填充表单信息
            ProcessFormUtils.fillFormData(formConf, historicProcIns.getProcessVariables());
        }
        return formConf;
    }
    
    @Override
    public WfDeployForm selectDeployExternalForm(String definitionId, String deployId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(definitionId);
        if (ObjectUtil.isNull(bpmnModel)) {
            throw new RuntimeException("获取流程信息失败！");
        }
        StartEvent startEvent = ModelUtils.getStartEvent(bpmnModel);
        WfDeployForm deployForm = deployFormMapper.selectOne(new LambdaQueryWrapper<WfDeployForm>()
            .eq(WfDeployForm::getDeployId, deployId)
            .eq(WfDeployForm::getFormKey, startEvent.getFormKey())
            .eq(WfDeployForm::getNodeKey, startEvent.getId()));
        return deployForm;
    }

    /**
     * 根据流程定义ID启动流程实例
     *
     * @param procDefId 流程定义Id
     * @param variables 流程变量
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void startProcessByDefId(String procDefId, Map<String, Object> variables) {
        try {
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(procDefId).singleResult();
            startProcess(processDefinition, variables);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("流程启动错误");
        }
    }

    /**
     * 通过DefinitionKey启动流程
     * @param procDefKey 流程定义Key
     * @param variables 扩展参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void startProcessByDefKey(String procDefKey, Map<String, Object> variables) {
        try {
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(procDefKey).latestVersion().singleResult();
            startProcess(processDefinition, variables);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("流程启动错误");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteProcessByIds(List<String> instanceIds) {
    	//查询是否存在运行中的流程
    	List<Task> runtimeTask = taskService.createTaskQuery().processInstanceIdIn(instanceIds).list();
    	if(runtimeTask!=null&&runtimeTask.size()>0) {
    		//结束流程
    		for(Task task:runtimeTask) {
    			// 获取所有节点信息
                BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
                EndEvent endEvent = ModelUtils.getEndEvent(bpmnModel);
                // 终止流程
                List<Execution> executions = runtimeService.createExecutionQuery().parentId(task.getProcessInstanceId()).list();
                List<String> executionIds = executions.stream().map(Execution::getId).collect(Collectors.toList());
                runtimeService.createChangeActivityStateBuilder()
                    .processInstanceId(task.getProcessInstanceId())
                    .moveExecutionsToSingleActivityId(executionIds, endEvent.getId())
                    .changeState();
    		}
    	}
    	//删除记录
        historyService.bulkDeleteHistoricProcessInstances(instanceIds);
    }

    /**
     * 读取xml文件
     * @param processDefId 流程定义ID
     */
    @Override
    public String queryBpmnXmlById(String processDefId) {
        InputStream inputStream = repositoryService.getProcessModel(processDefId);
        try {
            return IoUtil.readUtf8(inputStream);
        } catch (IORuntimeException exception) {
            throw new RuntimeException("加载xml文件异常");
        }
    }

    /**
     * 流程详情信息
     *
     * @param procInsId 流程实例ID
     * @param taskId 任务ID
     * @param businessKey 业务主键
     * 
     * @return
     */
    @Override
    public ResponseData<WfDetailVo> queryProcessDetail(String procInsId, String taskId, String businessKey) {
        WfDetailVo detailVo = new WfDetailVo();
        // 获取流程实例
        HistoricProcessInstance historicProcIns = historyService.createHistoricProcessInstanceQuery()
            .processInstanceId(procInsId)
            .processInstanceBusinessKey(businessKey)
            .includeProcessVariables()
            .singleResult();
        
        if(historicProcIns==null) {
        	return ResponseData.errorMsg("流程已不存在！");
        }else {
        	if(!StringUtil.isEmpty(taskId)) {
        		HistoricTaskInstance hisTaskInstance = historyService.createHistoricTaskInstanceQuery()
            			.taskId(taskId)
            			.processInstanceId(procInsId)
            			.singleResult();
            	if(hisTaskInstance==null) {
            		return ResponseData.errorMsg("任务已不存在！");
            	}else {
            		String owner = hisTaskInstance.getOwner();
            		if(StringUtil.isEmpty(owner)||super.getSysUser().getUserId().toString().equals(owner)) {
            			//非委派任务
            			detailVo.setIsDelegate(false);
            		}else {
            			//委派任务
            			detailVo.setIsDelegate(true);
            		}
            	}
        	}else {
        		detailVo.setIsDelegate(false);
        	}
        	
        	// 获取Bpmn模型信息
            InputStream inputStream = repositoryService.getProcessModel(historicProcIns.getProcessDefinitionId());
            String bpmnXmlStr = StrUtil.utf8Str(IoUtil.readBytes(inputStream, false));
            BpmnModel bpmnModel = ModelUtils.getBpmnModel(bpmnXmlStr);
            detailVo.setBpmnXml(bpmnXmlStr);
            detailVo.setHistoryProcNodeList(historyProcNodeList(historicProcIns));
            detailVo.setFlowViewer(getFlowViewer(bpmnModel, procInsId));
            return ResponseData.successData(detailVo);
        	
        }
    }

    /**
     * 启动流程实例
     */
    private void startProcess(ProcessDefinition procDef, Map<String, Object> variables) {
        if (ObjectUtil.isNotNull(procDef) && procDef.isSuspended()) {
            throw new ServiceException("流程已被挂起，请先激活流程");
        }
        // 设置流程发起人Id到流程中
        String userIdStr = String.valueOf(super.getSysUser().getUserId());
        identityService.setAuthenticatedUserId(userIdStr);
        variables.put(BpmnXMLConstants.ATTRIBUTE_EVENT_START_INITIATOR, userIdStr);
        // 设置流程状态为进行中
        variables.put(ProcessConstants.PROCESS_STATUS_KEY, ProcessStatus.RUNNING.getStatus());
        // 发起流程实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDef.getId(), variables);
        // 第一个用户任务为发起人，则自动完成任务
        wfTaskService.startFirstTask(processInstance, variables);
    }
    
    /**
     * 启动流程实例
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String startProcessInstance(String procDefId, String businessKey, Map<String, Object> variables) {
    	ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(procDefId).singleResult();
        if (ObjectUtil.isNotNull(procDef) && procDef.isSuspended()) {
            throw new ServiceException("流程已被挂起，无法申请！");
        }
        // 设置流程发起人Id到流程中
        String userIdStr = String.valueOf(super.getSysUser().getUserId());
        identityService.setAuthenticatedUserId(userIdStr);
        
        if(variables==null) {
        	variables = new HashMap<>();
        }
        variables.put(BpmnXMLConstants.ATTRIBUTE_EVENT_START_INITIATOR, userIdStr);
        variables.put(ProcessConstants.PROCESS_STARTER_NICKNAME, super.getSysUser().getNickName());
        variables.put(ProcessConstants.PROCESS_STARTER_DEPTNAME, super.getSysUser().getDept().getDeptName());
        // 设置流程状态为进行中
//        variables.put(ProcessConstants.PROCESS_STATUS_KEY, ProcessStatus.RUNNING.getStatus());
        variables.put(ProcessConstants.BUSINESS_KEY, businessKey);
        variables.put(ProcessConstants.PROCESS_START_TIME, DateUtil.getCurrentDate(DateUtil.FORMAT_YMDHMS_L));
        // 发起流程实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDef.getId(), businessKey, variables);
        // 第一个用户任务为发起人，则自动完成任务
        boolean completeFirstTask = wfTaskService.startFirstTask(processInstance, variables);
        
        //更新申请记录表
		WfApplyRecord wfApplyRecord = new WfApplyRecord();
		wfApplyRecord.setProcessInstanceId(processInstance.getId());
		if(completeFirstTask) {
			//审批中
			wfApplyRecord.setApprovalStatus(ApprovalStatus.RUNNING.getStatus());
		}else {
			//等待审批
			wfApplyRecord.setApprovalStatus(ApprovalStatus.WAITING.getStatus());
		}
		wfApplyRecord.setUpdateTime(new Date());
		
		UpdateWrapper<WfApplyRecord> updateWrapper = new UpdateWrapper<>();
		updateWrapper.lambda()
						.eq(WfApplyRecord::getUserId, super.getSysUser().getUserId())
						.eq(WfApplyRecord::getBusinessKey, businessKey);
		
		this.wfApplyRecordMapper.update(wfApplyRecord, updateWrapper);
		
        return processInstance.getId();
    }


    /**
     * 获取流程变量
     *
     * @param taskId 任务ID
     * @return 流程变量
     */
    public Map<String, Object> getProcessVariables(String taskId) {
        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery()
            .includeProcessVariables()
            .finished()
            .taskId(taskId)
            .singleResult();
        if (Objects.nonNull(historicTaskInstance)) {
            return historicTaskInstance.getProcessVariables();
        }
        return taskService.getVariables(taskId);
    }
    
    /**
     * 获取历史任务信息列表
     */
    private List<WfProcNodeVo> historyProcNodeList(HistoricProcessInstance historicProcIns) {
        String procInsId = historicProcIns.getId();
        List<HistoricActivityInstance> historicActivityInstanceList =  historyService.createHistoricActivityInstanceQuery()
            .processInstanceId(procInsId)
            .activityTypes(CollUtil.newHashSet(BpmnXMLConstants.ELEMENT_EVENT_START, BpmnXMLConstants.ELEMENT_EVENT_END, BpmnXMLConstants.ELEMENT_TASK_USER))
            .orderByHistoricActivityInstanceStartTime().desc()
            .orderByHistoricActivityInstanceEndTime().desc()
            .list();

        List<Comment> commentList = taskService.getProcessInstanceComments(procInsId);

        List<WfProcNodeVo> elementVoList = new ArrayList<>();
        for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
            WfProcNodeVo elementVo = new WfProcNodeVo();
            elementVo.setProcDefId(activityInstance.getProcessDefinitionId());
            elementVo.setActivityId(activityInstance.getActivityId());
            elementVo.setActivityName(activityInstance.getActivityName());
            elementVo.setActivityType(activityInstance.getActivityType());
            elementVo.setCreateTime(activityInstance.getStartTime());
            elementVo.setEndTime(activityInstance.getEndTime());
            
            if (BpmnXMLConstants.ELEMENT_EVENT_START.equals(activityInstance.getActivityType())) {
                if (ObjectUtil.isNotNull(historicProcIns)) {
                	elementVo.setProcName(historicProcIns.getProcessDefinitionName());
                    Long userId = Long.parseLong(historicProcIns.getStartUserId());
                    elementVo.setAssigneeId(userId);
                    elementVo.setAssigneeName(String.valueOf(
                    		historicProcIns.getProcessVariables().get(ProcessConstants.PROCESS_STARTER_NICKNAME)));
                }
            } else if (BpmnXMLConstants.ELEMENT_TASK_USER.equals(activityInstance.getActivityType())) {
                if (StringUtils.isNotBlank(activityInstance.getAssignee())) {
                    Long userId = Long.parseLong(activityInstance.getAssignee());
                    elementVo.setAssigneeId(userId);
                    String assigneeName = String.valueOf(
                    		historicProcIns.getProcessVariables().get(ProcessConstants.NODE_COMPLETE_NICKNAME + activityInstance.getTaskId())); 
                    if(StringUtil.isEmpty(assigneeName)) {
                    	assigneeName = "";
                    }
                    elementVo.setAssigneeName(assigneeName);
                }
                
                // 获取意见评论内容
                if (CollUtil.isNotEmpty(commentList)) {
                    List<Comment> comments = new ArrayList<>();
                    for (Comment comment : commentList) {

                        if (comment.getTaskId().equals(activityInstance.getTaskId())) {
                            comments.add(comment);
                        }
                    }
                    elementVo.setCommentList(comments);
                }
            }
            elementVoList.add(elementVo);
        }
        return elementVoList;
    }

    /**
     * 获取流程执行过程
     *
     * @param procInsId
     * @return
     */
    private WfViewerVo getFlowViewer(BpmnModel bpmnModel, String procInsId) {
        // 构建查询条件
        HistoricActivityInstanceQuery query = historyService.createHistoricActivityInstanceQuery()
            .processInstanceId(procInsId);
        List<HistoricActivityInstance> allActivityInstanceList = query.list();
        if (CollUtil.isEmpty(allActivityInstanceList)) {
            return new WfViewerVo();
        }
        // 查询所有已完成的元素
        List<HistoricActivityInstance> finishedElementList = allActivityInstanceList.stream()
            .filter(item -> ObjectUtil.isNotNull(item.getEndTime())).collect(Collectors.toList());
        // 所有已完成的连线
        Set<String> finishedSequenceFlowSet = new HashSet<>();
        // 所有已完成的任务节点
        Set<String> finishedTaskSet = new HashSet<>();
        finishedElementList.forEach(item -> {
            if (BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW.equals(item.getActivityType())) {
                finishedSequenceFlowSet.add(item.getActivityId());
            } else {
                finishedTaskSet.add(item.getActivityId());
            }
        });
        // 查询所有未结束的节点
        Set<String> unfinishedTaskSet = allActivityInstanceList.stream()
            .filter(item -> ObjectUtil.isNull(item.getEndTime()))
            .map(HistoricActivityInstance::getActivityId)
            .collect(Collectors.toSet());
        // DFS 查询未通过的元素集合
        Set<String> rejectedSet = FlowableUtils.dfsFindRejects(bpmnModel, unfinishedTaskSet, finishedSequenceFlowSet, finishedTaskSet);
        return new WfViewerVo(finishedTaskSet, finishedSequenceFlowSet, unfinishedTaskSet, rejectedSet);
    }
}
